package net.pws.oos.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.pws.common.persistence.EntityManager;
import net.pws.common.security.SecurityContext;
import net.pws.common.security.filter.AbstractAuthenticateFilter;
import net.pws.common.security.spi.Principal;
import net.pws.common.security.spi.resource.Resource;
import net.pws.oos.web.dto.ResourceDto;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MenuPopulator extends AbstractAuthenticateFilter {
    
    public static final Log logger = LogFactory.getLog(MenuPopulator.class);
    
    private static final String FILTER_APPLIED = "__MenuPopulator_filterApplied";
    
    private EntityManager entityManager;
    
    public EntityManager getEntityManager() {
        return entityManager;
    }
    
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) throws IOException,
                                           ServletException {
        if (request.getAttribute(FILTER_APPLIED) != null) {
            chain.doFilter(request, response);
            return;
        }
        
        if (!(request instanceof HttpServletRequest)) {
            throw new ServletException("Can only process HttpServletRequest");
        }
        
        if (!(response instanceof HttpServletResponse)) {
            throw new ServletException("Can only process HttpServletResponse");
        }
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        String uri = httpRequest.getRequestURI();
        if (uri.endsWith(".json")) {
            chain.doFilter(request, response);
            return;
        }
        
        Principal principal = SecurityContext.getContext();
        if (principal == null) {
            chain.doFilter(request, response);
            return;
        }
        
        List<ResourceDto> topMenu = new ArrayList<ResourceDto>();
        List<ResourceDto> subMenu = new ArrayList<ResourceDto>();
        
        List<Resource> resources = getMenu(principal.getId());
        for (int i = 0; i < resources.size(); i++) {
            Resource resource = resources.get(i);
            if (resource.getDepth() == 0) {
                topMenu.add(ResourceDto.from(resource));
            }
            
            if (uri.startsWith(resource.getUrl())) {
                List<Resource> subResources = getMenu(principal.getId(),
                                                        resource.getId());
                for (int j = 0; j < subResources.size(); j++) {
                    Resource subResource = subResources.get(j);
                    subMenu.add(ResourceDto.from(subResource));
                }
            }
        }
        
        request.setAttribute("topMenu", topMenu);
        request.setAttribute("subMenu", subMenu);
        request.setAttribute("currentUser", SecurityContext.getContext()
                                                           .getDetail());
        request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
        
        chain.doFilter(request, response);
    }
    
    protected List<Resource> getMenu(String userId) {
        return (List<Resource>) entityManager.findList("select distinct res from Permission p left join p.resource res left join res.parent,User u left join u.roles r where res.depth = 0 and p.role.id = r.id and p.resource.type = ? and u.id = ? order by res.code",
                                                       new Object[] { "menu",
                                                                     userId });
    }
    
    protected List<Resource> getMenu(String userId, String resourceId) {
        return (List<Resource>) entityManager.findList("select distinct res from Permission p left join p.resource res left join res.parent,User u left join u.roles r where p.role.id = r.id and p.resource.type = ? and u.id = ? and res.parent.id = ? order by res.code",
                                                       new Object[] { "menu",
                                                                     userId,
                                                                     resourceId });
    }
    
}
